home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 2: CDPD 1
/
Almathera Ten on Ten - Disc 2: CDPD 1.iso
/
pd
/
101-125
/
118
/
empire
/
src
/
source.zoo
/
fileio.d
< prev
next >
Wrap
Text File
|
1987-12-02
|
18KB
|
761 lines
#include:util.g
#empire.g
#empfunc.g
uint
OS_BLOCK_SIZE = 512 - 4 * 6,
SECTOR_CACHE_SIZE = 100,
SHIP_CACHE_SIZE = 100;
type
SectorCache_t = struct {
*SectorCache_t sc_next, sc_prev; /* next, prev in LRU chain */
bool sc_dirty; /* needs writing to disk */
ushort sc_row, sc_col; /* absolute co-ords */
Sector_t sc_sector; /* the sector data */
},
ShipCache_t = struct {
*ShipCache_t shc_next, shc_prev;
bool shc_dirty;
uint shc_shipNumber;
Ship_t shc_ship;
};
[SECTOR_CACHE_SIZE] SectorCache_t SectorCache; /* the sector cache */
uint SectorFree; /* next unused slot */
*SectorCache_t SectorHead; /* head of LRU chain */
*SectorCache_t SectorTail; /* tail of LRU chain */
[SHIP_CACHE_SIZE] ShipCache_t ShipCache;
uint ShipFree;
*ShipCache_t ShipHead, ShipTail;
file(OS_BLOCK_SIZE * 1) SectorFile; /* yes, ONE disk block */
file(OS_BLOCK_SIZE * 1) ShipFile;
file(OS_BLOCK_SIZE * 1) TelegramFile;
file(OS_BLOCK_SIZE * 1) FleetFile;
file(OS_BLOCK_SIZE * 1) LoanFile;
file(OS_BLOCK_SIZE * 1) OfferFile;
file() NewsFile;
channel input binary SectorIn;
channel output binary SectorOut;
channel input binary ShipIn;
channel output binary ShipOut;
channel input binary TelegramIn;
channel output binary TelegramOut;
channel input binary FleetIn;
channel output binary FleetOut;
channel input binary LoanIn;
channel output binary LoanOut;
channel input binary OfferIn;
channel output binary OfferOut;
channel input binary NewsIn;
channel output binary NewsOut;
uint Receiver; /* receiver of open telegram */
/*
* closeEmpireFile - do the actual file closing.
*/
proc closeEmpireFile()void:
close(OfferOut);
close(OfferIn);
close(LoanOut);
close(LoanIn);
close(FleetOut);
close(FleetIn);
close(ShipOut);
close(ShipIn);
close(SectorOut);
close(SectorIn);
corp;
/*
* abort - abort with a message.
*/
proc abort(*char message)void:
writeln(Chout; "*** ", message, " - aborting");
if UsingSerial then
writeln("*** ", message, " - aborting");
fi;
closeEmpireFile();
if SerialOpen then
closeSerialHandler();
fi;
writeln(LogChannel; "*** ABORT: ", message);
close(LogChannel);
exit(1);
corp;
/*
* sectorFlush - flush the sector cache. We flush the sectors in increasing
* absolute sector order, so as to minimize disk seeking.
*/
proc sectorFlush()void:
uint minRow, minCol, i;
bool foundDirty;
*SectorCache_t lowest, sc;
if SectorFree ~= 0 then
while
foundDirty := false;
minRow := 0xffff;
minCol := 0xffff;
sc := &SectorCache[0];
for i from 0 upto SectorFree - 1 do
if sc*.sc_dirty and
(sc*.sc_row < minRow or
sc*.sc_row = minRow and
sc*.sc_col < minCol) then
foundDirty := true;
lowest := sc;
minRow := sc*.sc_row;
minCol := sc*.sc_col;
fi;
sc := sc + sizeof(SectorCache_t);
od;
foundDirty
do
if not SeekOut(SectorOut, sizeof(World_t) +
COUNTRY_MAX * sizeof(Country_t) +
(make(minRow, ulong) * World.w_columns + minCol) *
sizeof(Sector_t))
then
abort("Can't seek to sector");
fi;
if not write(SectorOut; lowest*.sc_sector) then
abort("Can't write sector");
fi;
lowest*.sc_dirty := false;
od;
fi;
corp;
/*
* sectorLookup - lookup/enter the requested sector in the sector cache.
* Return 'false' if it was already there. Referencing it will always
* put it at the head of the chain.
*/
proc sectorLookup(uint r, c)bool:
uint dirtyCount;
*SectorCache_t sc;
sc := SectorHead;
while sc ~= nil and
(sc*.sc_row ~= r or sc*.sc_col ~= c) do
sc := sc*.sc_next;
od;
if sc = nil then
/* didn't find the needed sector - add it to the cache. */
if SectorFree ~= SECTOR_CACHE_SIZE then
/* free slot left - just use it */
sc := &SectorCache[SectorFree];
SectorFree := SectorFree + 1;
else
/* no free slot - look for a non-dirty one */
dirtyCount := 0;
sc := SectorTail;
while sc ~= nil and sc*.sc_dirty do
sc := sc*.sc_prev;
dirtyCount := dirtyCount + 1;
od;
if dirtyCount > SECTOR_CACHE_SIZE * 4 / 5 or sc = nil then
/* no non-dirty slot left. Flush all and use tail one. */
sectorFlush();
sc := SectorTail;
fi;
/* delete the sector from it's current position in the chain */
if sc*.sc_prev = nil then
SectorHead := sc*.sc_next;
else
sc*.sc_prev*.sc_next := sc*.sc_next;
fi;
if sc*.sc_next = nil then
SectorTail := sc*.sc_prev;
else
sc*.sc_next*.sc_prev := sc*.sc_prev;
fi;
fi;
/* insert it at the head of the chain */
sc*.sc_prev := nil;
sc*.sc_next := SectorHead;
if SectorHead ~= nil then
SectorHead*.sc_prev := sc;
else
SectorTail := sc;
fi;
SectorHead := sc;
/* set it to be the requested sector */
sc*.sc_row := r;
sc*.sc_col := c;
sc*.sc_dirty := false;
true
else
/* move it to the front of the LRU chain if its not there already */
if sc*.sc_prev ~= nil then
sc*.sc_prev*.sc_next := sc*.sc_next;
if sc*.sc_next ~= nil then
sc*.sc_next*.sc_prev := sc*.sc_prev;
else
SectorTail := sc*.sc_prev;
fi;
sc*.sc_prev := nil;
sc*.sc_next := SectorHead;
if SectorHead ~= nil then
SectorHead*.sc_prev := sc;
else
SectorTail := sc;
fi;
SectorHead := sc;
fi;
false
fi
corp;
/*
* shipFlush - flush the ship cache. We flush the ships in increasing
* ship number order, so as to minimize disk seeking.
*/
proc shipFlush()void:
uint minNum, i;
bool foundDirty;
*ShipCache_t lowest, shc;
if ShipFree ~= 0 then
while
foundDirty := false;
minNum := 0xffff;
shc := &ShipCache[0];
for i from 0 upto ShipFree - 1 do
if shc*.shc_dirty and shc*.shc_shipNumber < minNum then
foundDirty := true;
lowest := shc;
minNum := shc*.shc_shipNumber;
fi;
shc := shc + sizeof(ShipCache_t);
od;
foundDirty
do
if not SeekOut(ShipOut, make(minNum, ulong) * sizeof(Ship_t)) then
abort("Can't seek to ship");
fi;
if not write(ShipOut; lowest*.shc_ship) then
abort("Can't write ship");
fi;
lowest*.shc_dirty := false;
od;
fi;
corp;
/*
* shipLookup - lookup/enter the requested ship in the ship cache.
* Return 'false' if it was already there. Referencing it will always
* put it at the head of the chain.
*/
proc shipLookup(uint shipNumber)bool:
uint dirtyCount;
*ShipCache_t shc;
shc := ShipHead;
while shc ~= nil and shc*.shc_shipNumber ~= shipNumber do
shc := shc*.shc_next;
od;
if shc = nil then
/* didn't find the needed sector - add it to the cache. */
if ShipFree ~= SHIP_CACHE_SIZE then
/* free slot left - just use it */
shc := &ShipCache[ShipFree];
ShipFree := ShipFree + 1;
else
/* no free slot - look for a non-dirty one */
dirtyCount := 0;
shc := ShipTail;
while shc ~= nil and shc*.shc_dirty do
shc := shc*.shc_prev;
dirtyCount := dirtyCount + 1;
od;
if dirtyCount > SHIP_CACHE_SIZE * 4 / 5 or shc = nil then
/* no non-dirty slot left. Flush all and use tail one. */
shipFlush();
shc := ShipTail;
fi;
/* delete the ship from it's current position in the chain */
if shc*.shc_prev = nil then
ShipHead := shc*.shc_next;
else
shc*.shc_prev*.shc_next := shc*.shc_next;
fi;
if shc*.shc_next = nil then
ShipTail := shc*.shc_prev;
else
shc*.shc_next*.shc_prev := shc*.shc_prev;
fi;
fi;
/* insert it at the head of the chain */
shc*.shc_prev := nil;
shc*.shc_next := ShipHead;
if ShipHead ~= nil then
ShipHead*.shc_prev := shc;
else
ShipTail := shc;
fi;
ShipHead := shc;
/* set it to be the requested ship */
shc*.shc_shipNumber := shipNumber;
shc*.shc_dirty := false;
true
else
/* move it to the front of the LRU chain if its not there already */
if shc*.shc_prev ~= nil then
shc*.shc_prev*.shc_next := shc*.shc_next;
if shc*.shc_next ~= nil then
shc*.shc_next*.shc_prev := shc*.shc_prev;
else
ShipTail := shc*.shc_prev;
fi;
shc*.shc_prev := nil;
shc*.shc_next := ShipHead;
if ShipHead ~= nil then
ShipHead*.shc_prev := shc;
else
ShipTail := shc;
fi;
ShipHead := shc;
fi;
false
fi
corp;
/*
* closeFile - flush and close the empire data files.
*/
proc closeFile()void:
sectorFlush();
shipFlush();
closeEmpireFile();
corp;
/*
* openAbort - early abort when opening files.
*/
proc openAbort(*char which)void:
writeln(Chout; "*** can't open empire ", which, " file - aborting");
writeln(LogChannel; "*** can't open empire ", which, " file - aborting");
close(LogChannel);
if SerialOpen then
closeSerialHandler();
fi;
exit(1);
corp;
/*
* openFile - open the empire data files.
*/
proc openFile()void:
if not open(SectorIn, SectorFile, SECTOR_FILE) then
openAbort("sector");
fi;
ReOpen(SectorIn, SectorOut);
SectorFree := 0;
SectorHead := nil;
SectorTail := nil;
if not open(ShipIn, ShipFile, SHIP_FILE) then
close(SectorOut);
close(SectorIn);
openAbort("ship");
fi;
ReOpen(ShipIn, ShipOut);
ShipFree := 0;
ShipHead := nil;
ShipTail := nil;
if not open(FleetIn, FleetFile, FLEET_FILE) then
close(ShipOut);
close(ShipIn);
close(SectorOut);
close(SectorIn);
openAbort("fleet");
fi;
ReOpen(FleetIn, FleetOut);
if not open(LoanIn, LoanFile, LOAN_FILE) then
close(ShipOut);
close(ShipIn);
close(SectorOut);
close(SectorIn);
close(FleetOut);
close(FleetIn);
openAbort("loan");
fi;
ReOpen(LoanIn, LoanOut);
if not open(OfferIn, OfferFile, OFFER_FILE) then
close(ShipOut);
close(ShipIn);
close(SectorOut);
close(SectorIn);
close(FleetOut);
close(FleetIn);
close(LoanOut);
close(LoanIn);
openAbort("offer");
fi;
ReOpen(OfferIn, OfferOut);
corp;
/*
* readWorld - read the world header and user information
*/
proc readWorld()void:
if not SeekOut(SectorOut, 0) then
abort("Can't seek to header");
fi;
if not read(SectorIn; World) then
abort("Can't read world size");
fi;
if not read(SectorIn; Country) then
abort("Can't read users");
fi;
corp;
/*
* writeWorld - write the world header and user information
*/
proc writeWorld()void:
if not SeekOut(SectorOut, 0) then
abort("Can't seek to header");
fi;
if not write(SectorOut; World) then
abort("Can't write world size");
fi;
if not write(SectorOut; Country) then
abort("Can't write users");
fi;
corp;
/*
* readSector - read the given sector into a given buffer.
*/
proc readSector(int row, col; Sector_t s)void:
if sectorLookup(transRow(row), transCol(col)) then
if not SeekOut(SectorOut, sizeof(World_t) +
COUNTRY_MAX * sizeof(Country_t) +
(make(transRow(row), ulong) * World.w_columns +
transCol(col)) * sizeof(Sector_t)) then
abort("Can't seek to sector");
fi;
if not read(SectorIn; SectorHead*.sc_sector) then
abort("Can't read sector");
fi;
fi;
s := SectorHead*.sc_sector;
corp;
/*
* writeSector - write the given sector from a given buffer.
*/
proc writeSector(int row, col; Sector_t s)void:
pretend(sectorLookup(transRow(row), transCol(col)), void);
SectorHead*.sc_sector := s;
SectorHead*.sc_dirty := true;
corp;
/*
* readShip - read the given ship into a given buffer.
*/
proc readShip(uint shipNumber; Ship_t ship)void:
if shipLookup(shipNumber) then
if not SeekOut(ShipOut, make(shipNumber, ulong) * sizeof(Ship_t)) then
abort("Can't seek to ship");
fi;
if not read(ShipIn; ShipHead*.shc_ship) then
abort("Can't read ship");
fi;
fi;
ship := ShipHead*.shc_ship;
corp;
/*
* writeShip - write the given ship from a given buffer.
*/
proc writeShip(uint shipNumber; Ship_t ship)void:
pretend(shipLookup(shipNumber), void);
ShipHead*.shc_ship := ship;
ShipHead*.shc_dirty := true;
corp;
/*
* readFleet - read the given fleet into a given buffer.
*/
proc readFleet(uint fleetNumber; Fleet_t fleet)void:
if not SeekOut(FleetOut, make(fleetNumber, ulong) * sizeof(Fleet_t)) then
abort("Can't seek to fleet");
fi;
if not read(FleetIn; fleet) then
abort("Can't read fleet");
fi;
corp;
/*
* writeFleet - write the given fleet from a given buffer.
*/
proc writeFleet(uint fleetNumber; Fleet_t fleet)void:
if not SeekOut(FleetOut, make(fleetNumber, ulong) * sizeof(Fleet_t)) then
abort("Can't seek to fleet");
fi;
if not write(FleetOut; fleet) then
abort("Can't write fleet");
fi;
corp;
/*
* readLoan - read the given loan into a given buffer.
*/
proc readLoan(uint loanNumber; Loan_t loan)void:
if not SeekOut(LoanOut, make(loanNumber, ulong) * sizeof(Loan_t)) then
abort("Can't seek to loan");
fi;
if not read(LoanIn; loan) then
abort("Can't read loan");
fi;
corp;
/*
* writeLoan - write the given loan from a given buffer.
*/
proc writeLoan(uint loanNumber; Loan_t loan)void:
if not SeekOut(LoanOut, make(loanNumber, ulong) * sizeof(Loan_t)) then
abort("Can't seek to loan");
fi;
if not write(LoanOut; loan) then
abort("Can't write loan");
fi;
corp;
/*
* readOffer - read the given offer into a given buffer.
*/
proc readOffer(uint offerNumber; Offer_t offer)void:
if not SeekOut(OfferOut, make(offerNumber, ulong) * sizeof(Offer_t)) then
abort("Can't seek to offer");
fi;
if not read(OfferIn; offer) then
abort("Can't read offer");
fi;
corp;
/*
* writeOffer - write the given offer from a given buffer.
*/
proc writeOffer(uint offerNumber; Offer_t offer)void:
if not SeekOut(OfferOut, make(offerNumber, ulong) * sizeof(Offer_t)) then
abort("Can't seek to offer");
fi;
if not write(OfferOut; offer) then
abort("Can't write offer");
fi;
corp;
/*
* telegramChar - write a character to the current telegram.
*/
proc telegramChar(char ch)void:
write(TelegramOut; ch);
Country[Receiver].c_telegramsTail := Country[Receiver].c_telegramsTail + 1;
corp;
/*
* telegramStart - start the transmission of a telegram.
*/
proc telegramStart(uint sender, receiver)void:
*char p;
ulong ul;
p := "telegrams.XX";
(p + 10)* := receiver / 10 + '0';
(p + 11)* := receiver % 10 + '0';
if not open(TelegramOut, TelegramFile, p) then
abort("Can't open telegram file");
fi;
RandomOut(TelegramOut);
if Country[receiver].c_telegramsTail ~= 0 and
not SeekOut(TelegramOut, Country[receiver].c_telegramsTail) then
close(TelegramOut);
abort("can't seek to add telegram");
fi;
Receiver := receiver;
write(TelegramOut; sender);
ul := CurrentTime();
write(TelegramOut; ul);
Country[receiver].c_telegramsTail := Country[receiver].c_telegramsTail +
(sizeof(uint) + sizeof(ulong));
open(TelegramChannel, telegramChar);
corp;
/*
* telegramEnd - end the current telegram.
*/
proc telegramEnd()void:
close(TelegramChannel);
close(TelegramOut);
corp;
/*
* telegramOpen - open this user's telegram file for reading.
*/
proc telegramOpen()void:
*char p;
p := "telegrams.XX";
(p + 10)* := ThisCountryNumber / 10 + '0';
(p + 11)* := ThisCountryNumber % 10 + '0';
if not open(TelegramIn, TelegramFile, p) then
abort("Can't open telegram file");
fi;
corp;
/*
* telegramRead - read the next telegram and return the number of bytes read.
* Return '0' and close the file when there are no more to read.
*/
proc telegramRead(ulong endPosition)bool:
ulong time;
uint sender;
byte b;
if GetIn(TelegramIn) ~= endPosition and read(TelegramIn; sender, time) then
writeln(Chout;);
write(Chout; "Telegram from ", &Country[sender].c_name[0], " dated ");
writeDate(time);
writeln(Chout; ':');
writeln(Chout;);
while read(TelegramIn; b) and b ~= 0 do
write(Chout; b + '\e');
od;
writeln(Chout;);
true
else
close(TelegramIn);
false
fi
corp;
/*
* getNewsFileName - fill in a file name for news for the given time's day.
*/
proc getNewsFileName(*char buffer; ulong time)void:
channel output text dateChannel;
open(dateChannel, buffer);
write(dateChannel; "news.", time / (60 * 60 * 24));
close(dateChannel);
corp;
/*
* news - add a news item to today's news file.
*/
proc news(NewsType_t verb; uint actor, victim)void:
News_t n;
ulong now, position;
[15] char fileName;
now := CurrentTime();
n.n_verb := verb;
n.n_actor := actor;
n.n_victim := victim;
n.n_btu := Country[actor].c_btu;
n.n_time := now;
getNewsFileName(&fileName[0], now);
if not open(NewsOut, NewsFile, &fileName[0]) then
if not FileCreate(&fileName[0]) then
abort("can't create news file to add news");
fi;
if not open(NewsOut, NewsFile, &fileName[0]) then
abort("can't open news file to add news");
fi;
fi;
RandomOut(NewsOut);
position := GetOutMax(NewsOut);
if not SeekOut(NewsOut, position) then
close(NewsOut);
abort("can't seek to add news");
fi;
write(NewsOut; n);
close(NewsOut);
corp;
/*
* newsOpen - open a news file to read the whole contents.
* Return 'false' if none.
*/
proc newsOpen(ulong date)bool:
[15] char fileName;
getNewsFileName(&fileName[0], date);
if open(NewsIn, NewsFile, &fileName[0]) then
true
else
false
fi
corp;
/*
* newsNext - read the next news chunk from the current file.
* Close the file and return 'false' when none left.
*/
proc newsNext(News_t n)bool:
if read(NewsIn; n) then
true
else
close(NewsIn);
false
fi
corp;